package cn.rjzjh.tapestry.tams.services.base;

import static org.hibernate.criterion.Example.create;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.hibernate.Criteria;
import org.hibernate.LockOptions;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Example.PropertySelector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

public class HbService implements IHbService {
	private static Logger logger = LoggerFactory.getLogger(HbService.class);

	@Inject
	private Session session;

	@Override
	public final <T extends Serializable> T findById(Class clazz,
			Serializable id) {
		return (T) session.get(clazz, id);
	}

	public final void delById(Class clazz, Serializable entityId) {
		Object entity = session.get(clazz, entityId);
		Preconditions.checkState(entity != null);
		session.delete(entity);
	}

	@Override
	public final Query getQuery(String queryStr) {
		return session.createQuery(queryStr);
	}

	@SuppressWarnings("unchecked")
	@Override
	public final <T extends Serializable> List<T> findByExample(T entity,
			PropertySelector selector) {
		try {
			Example example = create(entity).excludeZeroes();
			if (selector != null) {
				example.setPropertySelector(selector);
			}
			List<T> results = (List<T>) session
					.createCriteria(entity.getClass()).add(example).list();
			return results;
		} catch (RuntimeException re) {
			logger.error("find by example failed", re);
			throw re;
		}
	}

	@Override
	public final <T extends Serializable> List<T> findByExample(T entity,
			String... excludes) {
		try {
			Example example = create(entity).excludeZeroes();
			if (ArrayUtils.isNotEmpty(excludes)) {
				for (String proName : excludes) {
					example.excludeProperty(proName);
				}
			}
			List<T> results = (List<T>) session
					.createCriteria(entity.getClass()).add(example).list();
			return results;
		} catch (RuntimeException re) {
			logger.error("find by example failed", re);
			throw re;
		}
	}

	/****
	 * Oracle/mysql 支持悲观锁的会用　select * from XXX for update 锁记录，其它数据库同 attachQuery
	 *
	 * @param entity
	 */
	public final <T extends Serializable> void attachLock(T entity) {
		try {
			session.buildLockRequest(LockOptions.UPGRADE).lock(entity);
		} catch (RuntimeException re) {
			logger.error("attach failed", re);
			throw re;
		}
	}

	@Override
	public final <T extends Serializable> List<T> findByExamplePage(T entity,
			int pageNo, int pageSize, String... excludes) {
		try {
			Example example = create(entity).excludeZeroes();
			if (ArrayUtils.isNotEmpty(excludes)) {
				for (String proName : excludes) {
					example.excludeProperty(proName);
				}
			}
			Criteria criteria = session.createCriteria(entity.getClass()).add(
					example);
			return findByCriteriaPage(criteria, pageNo, pageSize);
		} catch (RuntimeException re) {
			logger.error("find by example failed", re);
			throw re;
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public final <T extends Serializable> List<T> findByCriteriaPage(
			Criteria criteria, int pageNo, int pageSize) {
		Preconditions
				.checkState(criteria != null && pageNo > 0 && pageSize > 0);
		int min = (pageNo - 1) * pageSize;
		criteria.setFirstResult(min).setMaxResults(pageSize);
		return criteria.list();
	}

	@Override
	@SuppressWarnings("unchecked")
	public final <T extends Serializable> List<T> findByQueryPage(Query query,
			int pageNo, int pageSize) {
		Preconditions.checkState(query != null && pageNo > 0 && pageSize > 0);
		int min = (pageNo - 1) * pageSize;
		return query.setFirstResult(min).setMaxResults(pageSize).list();
	}

	@Override
	public final <T extends Serializable> List<T> findByHqlPage(String hql,
			int pageNo, int pageSize) {
		return findByQueryPage(getQuery(hql), pageNo, pageSize);
	}

	@Override
	public Query getQuerySQL(String sql) {
		return session.createSQLQuery(sql);
	}

	// 不起作用
	@Override
	public <T extends Serializable> void saveOrUpdate(T obj) {
		session.saveOrUpdate(obj);
	}
}
